home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / source / chapter23 / isohex23_1 / isohex23_1.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-29  |  12.9 KB  |  538 lines

  1. /*****************************************************************************
  2. IsoHex23_1.cpp
  3. Ernest S. Pazera
  4. 29NOV2000
  5. Start a WIN32 Application Workspace, add in this file
  6. Requires GDICanvas.h/cpp
  7. No other libs are required
  8. *****************************************************************************/
  9.  
  10. //////////////////////////////////////////////////////////////////////////////
  11. //INCLUDES
  12. //////////////////////////////////////////////////////////////////////////////
  13. #define WIN32_LEAN_AND_MEAN  
  14.  
  15. #include <windows.h>   
  16. #include <stdlib.h>
  17. #include "gdicanvas.h"
  18.  
  19. //////////////////////////////////////////////////////////////////////////////
  20. //DEFINES
  21. //////////////////////////////////////////////////////////////////////////////
  22. //name for our window class
  23. #define WINDOWCLASS "ISOHEX23"
  24. //title of the application
  25. #define WINDOWTITLE "IsoHex 23-1"
  26.  
  27. //dimensions of map
  28. const int MAPWIDTH=16;
  29. const int MAPHEIGHT=16;
  30. //dimensions of tiles
  31. const int TILEWIDTH=16;
  32. const int TILEHEIGHT=16;
  33.  
  34. //names of tiles
  35. const int TILEEMPTY=0;
  36. const int TILEBLOCK=1;
  37. const int TILESTART=2;
  38. const int TILEEND=3;
  39. const int TILEPATH=4;
  40. const int TILESELECT=5;
  41.  
  42. //////////////////////////////////////////////////////////////////////////////
  43. //PROTOTYPES
  44. //////////////////////////////////////////////////////////////////////////////
  45. bool Prog_Init();//game data initalizer
  46. void Prog_Loop();//main game loop
  47. void Prog_Done();//game clean up
  48. void FindPath();//find the map
  49. void PutTile(int x,int y,int tilenum);//put a tile
  50. void DrawMap();//draw the map
  51. void PlaceTile(int x,int y, int tilenum);//place a tile on the map
  52.  
  53. //////////////////////////////////////////////////////////////////////////////
  54. //GLOBALS
  55. //////////////////////////////////////////////////////////////////////////////
  56. HINSTANCE hInstMain=NULL;//main application handle
  57. HWND hWndMain=NULL;//handle to our main window
  58.  
  59. //map for the ai
  60. CGDICanvas gdicMap;
  61. //images for ai items
  62. CGDICanvas gdicAI;
  63.  
  64. //map
  65. int Map[MAPWIDTH][MAPHEIGHT];//contains tile data about the map
  66. int MapPath[MAPWIDTH][MAPHEIGHT];//contains pathfinding info about the map
  67. //map marks
  68. bool MapMark[MAPWIDTH][MAPHEIGHT];//contains marked tiles for pathfinding
  69. //currently selected tile
  70. int TileSelected=0;
  71.  
  72. //////////////////////////////////////////////////////////////////////////////
  73. //WINDOWPROC
  74. //////////////////////////////////////////////////////////////////////////////
  75. LRESULT CALLBACK TheWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
  76. {
  77.     //which message did we get?
  78.     switch(uMsg)
  79.     {
  80.     case WM_LBUTTONDOWN:
  81.         {
  82.             //get x and y positions
  83.             int x=LOWORD(lParam);
  84.             int y=HIWORD(lParam);
  85.             //divide x and y by the tilewidth and tileheight
  86.             x/=TILEWIDTH;
  87.             y/=TILEHEIGHT;
  88.             //decide if we are on the map or the toolbar
  89.             if(y<MAPHEIGHT)
  90.             {
  91.                 //we are in the map
  92.                 PlaceTile(x,y,TileSelected);
  93.             }
  94.             else
  95.             {
  96.                 //we are in the toolbar
  97.                 //check if we are on one of the tiles
  98.                 if(x<4) TileSelected=x;
  99.                 DrawMap();
  100.                 InvalidateRect(hWndMain,NULL,FALSE);
  101.             }
  102.         }break;
  103.     case WM_DESTROY://the window is being destroyed
  104.         {
  105.  
  106.             //tell the application we are quitting
  107.             PostQuitMessage(0);
  108.  
  109.             //handled message, so return 0
  110.             return(0);
  111.  
  112.         }break;
  113.     case WM_PAINT://the window needs repainting
  114.         {
  115.             //a variable needed for painting information
  116.             PAINTSTRUCT ps;
  117.             
  118.             //start painting
  119.             HDC hdc=BeginPaint(hwnd,&ps);
  120.  
  121.             //redraw the map
  122.             BitBlt(hdc,0,0,TILEWIDTH*MAPWIDTH,TILEHEIGHT*MAPHEIGHT+TILEHEIGHT,gdicMap,0,0,SRCCOPY);
  123.  
  124.             //end painting
  125.             EndPaint(hwnd,&ps);
  126.                     
  127.             //handled message, so return 0
  128.             return(0);
  129.         }break;
  130.     }
  131.  
  132.     //pass along any other message to default message handler
  133.     return(DefWindowProc(hwnd,uMsg,wParam,lParam));
  134. }
  135.  
  136.  
  137. //////////////////////////////////////////////////////////////////////////////
  138. //WINMAIN
  139. //////////////////////////////////////////////////////////////////////////////
  140. int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
  141. {
  142.     //assign instance to global variable
  143.     hInstMain=hInstance;
  144.  
  145.     //create window class
  146.     WNDCLASSEX wcx;
  147.  
  148.     //set the size of the structure
  149.     wcx.cbSize=sizeof(WNDCLASSEX);
  150.  
  151.     //class style
  152.     wcx.style=CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
  153.  
  154.     //window procedure
  155.     wcx.lpfnWndProc=TheWindowProc;
  156.  
  157.     //class extra
  158.     wcx.cbClsExtra=0;
  159.  
  160.     //window extra
  161.     wcx.cbWndExtra=0;
  162.  
  163.     //application handle
  164.     wcx.hInstance=hInstMain;
  165.  
  166.     //icon
  167.     wcx.hIcon=LoadIcon(NULL,IDI_APPLICATION);
  168.  
  169.     //cursor
  170.     wcx.hCursor=LoadCursor(NULL,IDC_ARROW);
  171.  
  172.     //background color
  173.     wcx.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
  174.  
  175.     //menu
  176.     wcx.lpszMenuName=NULL;
  177.  
  178.     //class name
  179.     wcx.lpszClassName=WINDOWCLASS;
  180.  
  181.     //small icon
  182.     wcx.hIconSm=NULL;
  183.  
  184.     //register the window class, return 0 if not successful
  185.     if(!RegisterClassEx(&wcx)) return(0);
  186.  
  187.     //create main window
  188.     hWndMain=CreateWindowEx(0,WINDOWCLASS,WINDOWTITLE, WS_BORDER | WS_SYSMENU | WS_CAPTION| WS_VISIBLE,0,0,320,240,NULL,NULL,hInstMain,NULL);
  189.  
  190.     //error check
  191.     if(!hWndMain) return(0);
  192.  
  193.     //if program initialization failed, then return with 0
  194.     if(!Prog_Init()) return(0);
  195.  
  196.     //message structure
  197.     MSG msg;
  198.  
  199.     //message pump
  200.     for(;;)    
  201.     {
  202.         //look for a message
  203.         if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  204.         {
  205.             //there is a message
  206.  
  207.             //check that we arent quitting
  208.             if(msg.message==WM_QUIT) break;
  209.             
  210.             //translate message
  211.             TranslateMessage(&msg);
  212.  
  213.             //dispatch message
  214.             DispatchMessage(&msg);
  215.         }
  216.  
  217.         //run main game loop
  218.         Prog_Loop();
  219.     }
  220.     
  221.     //clean up program data
  222.     Prog_Done();
  223.  
  224.     //return the wparam from the WM_QUIT message
  225.     return(msg.wParam);
  226. }
  227.  
  228. //////////////////////////////////////////////////////////////////////////////
  229. //INITIALIZATION
  230. //////////////////////////////////////////////////////////////////////////////
  231. bool Prog_Init()
  232. {
  233.     //set the client area size
  234.     RECT rcTemp;
  235.     SetRect(&rcTemp,0,0,MAPWIDTH*TILEWIDTH,MAPHEIGHT*TILEHEIGHT+TILEHEIGHT);//256x256 client area
  236.     AdjustWindowRect(&rcTemp,WS_BORDER | WS_SYSMENU | WS_CAPTION| WS_VISIBLE,FALSE);//adjust the window size based on desired client area
  237.     SetWindowPos(hWndMain,NULL,0,0,rcTemp.right-rcTemp.left,rcTemp.bottom-rcTemp.top,SWP_NOMOVE);//set the window width and height
  238.  
  239.     //create map image
  240.     HDC hdc=GetDC(hWndMain);
  241.     gdicMap.CreateBlank(hdc,MAPWIDTH*TILEWIDTH,MAPHEIGHT*TILEHEIGHT+TILEHEIGHT);
  242.     FillRect(gdicMap,&rcTemp,(HBRUSH)GetStockObject(BLACK_BRUSH));
  243.     ReleaseDC(hWndMain,hdc);
  244.  
  245.     //load in tiles
  246.     gdicAI.Load(NULL,"ai.bmp");
  247.  
  248.     //start out the map
  249.     for(int x=0;x<MAPWIDTH;x++)
  250.     {
  251.         for(int y=0;y<MAPHEIGHT;y++)
  252.         {
  253.             Map[x][y]=TILEEMPTY;
  254.         }
  255.     }
  256.     //set initial start and end points
  257.     Map[0][0]=TILESTART;
  258.     Map[MAPWIDTH-1][MAPHEIGHT-1]=TILEEND;
  259.     //draw the map
  260.     DrawMap();
  261.  
  262.     return(true);//return success
  263. }
  264.  
  265. //////////////////////////////////////////////////////////////////////////////
  266. //CLEANUP
  267. //////////////////////////////////////////////////////////////////////////////
  268. void Prog_Done()
  269. {
  270.     //////////////////////////
  271.     //clean up code goes here
  272.     //////////////////////////
  273. }
  274.  
  275. //////////////////////////////////////////////////////////////////////////////
  276. //MAIN GAME LOOP
  277. //////////////////////////////////////////////////////////////////////////////
  278. void Prog_Loop()
  279. {
  280.     ///////////////////////////
  281.     //main game logic goes here
  282.     ///////////////////////////
  283. }
  284.  
  285. void FindPath()//find the path
  286. {
  287.     POINT ptStart;
  288.     POINT ptEnd;
  289.     POINT ptPath;
  290.     ptStart.x=-1;
  291.     ptEnd.x=-1;
  292.     int x;
  293.     int y;
  294.     int nx;
  295.     int ny;
  296.     bool found;
  297.     int lowvalue;
  298.     //find the start
  299.     for(x=0;x<MAPWIDTH;x++)
  300.     {
  301.         for(y=0;y<MAPHEIGHT;y++)
  302.         {
  303.             //check for the start
  304.             if(Map[x][y]==TILESTART)
  305.             {
  306.                 ptStart.x=x;
  307.                 ptStart.y=y;
  308.             }
  309.         }
  310.     }
  311.     //find the end
  312.     for(x=0;x<MAPWIDTH;x++)
  313.     {
  314.         for(y=0;y<MAPHEIGHT;y++)
  315.         {
  316.             //check for the end
  317.             if(Map[x][y]==TILEEND)
  318.             {
  319.                 ptEnd.x=x;
  320.                 ptEnd.y=y;
  321.             }
  322.         }
  323.     }
  324.     //if no start or end, exit function
  325.     if(ptStart.x==-1 || ptEnd.x==-1) return;
  326.     //fill out the path array
  327.     for(x=0;x<MAPWIDTH;x++)
  328.     {
  329.         for(y=0;y<MAPHEIGHT;y++)
  330.         {
  331.             switch(Map[x][y])
  332.             {
  333.             case TILESTART://place a 0 at the start
  334.                 {
  335.                     MapPath[x][y]=0;
  336.                 }break;
  337.             case TILEBLOCK://place a 999 at any blocks
  338.                 {
  339.                     MapPath[x][y]=999;
  340.                 }break;
  341.             case TILEEMPTY://if empty, place a -1
  342.                 {
  343.                     MapPath[x][y]=-1;
  344.                 }break;
  345.             default://anything else, place a -1
  346.                 {
  347.                     MapPath[x][y]=-1;
  348.                 }break;
  349.             }
  350.         }
  351.     }
  352.     //scan for pathable tiles
  353.     do
  354.     {
  355.         //havent found one yet
  356.         found=false;
  357.         //scan the map
  358.         for(x=0;x<MAPWIDTH;x++)
  359.         {
  360.             for(y=0;y<MAPHEIGHT;y++)
  361.             {
  362.                 MapMark[x][y]=false;
  363.                 //make sure this is a "-1" square
  364.                 if(MapPath[x][y]==-1)
  365.                 {
  366.                     //scan the neighbors
  367.                     for(nx=x-1;nx<=x+1;nx++)
  368.                     {
  369.                         for(ny=y-1;ny<=y+1;ny++)
  370.                         {
  371.                             //make sure the neighbor is on the map
  372.                             if(nx>=0 && ny>=0 && nx<MAPWIDTH && ny<MAPHEIGHT && !(nx==x && ny==y))
  373.                             {
  374.                                 //check against negatives and 999
  375.                                 if(MapPath[nx][ny]>=0 && MapPath[nx][ny]!=999)
  376.                                 {
  377.                                     //mark the map
  378.                                     MapMark[x][y]=true;
  379.                                     //mark it as found
  380.                                     found=true;
  381.                                 }
  382.                             }
  383.                         }
  384.                     }
  385.                 }
  386.             }
  387.         }
  388.         //now scan the marks
  389.         for(x=0;x<MAPWIDTH;x++)
  390.         {
  391.             for(y=0;y<MAPHEIGHT;y++)
  392.             {
  393.                 //if this square is marked
  394.                 if(MapMark[x][y])
  395.                 {
  396.                     //set low value very high
  397.                     lowvalue=999;
  398.                     //loop through neighbors
  399.                     for(nx=x-1;nx<=x+1;nx++)
  400.                     {
  401.                         for(ny=y-1;ny<=y+1;ny++)
  402.                         {
  403.                             //make sure the neighbor is on the map
  404.                             if(nx>=0 && ny>=0 && nx<MAPWIDTH && ny<MAPHEIGHT)
  405.                             {
  406.                                 if(MapPath[nx][ny]>=0)//must be a non-negative value
  407.                                 {
  408.                                     //assign the value if it is lower
  409.                                     if(MapPath[nx][ny]<lowvalue) lowvalue=MapPath[nx][ny];
  410.                                 }
  411.                             }
  412.                         }
  413.                     }
  414.                     //assign the value to the path map
  415.                     MapPath[x][y]=lowvalue+1;
  416.                 }
  417.             }
  418.         }
  419.     }
  420.     while(found);
  421.     //done with pathfinding
  422.     //check to see that ptEnd has found a path
  423.     if(MapPath[ptEnd.x][ptEnd.y]!=-1)
  424.     {
  425.         //start the path
  426.         ptPath=ptEnd;
  427.         //take the value from the map
  428.         lowvalue=MapPath[ptEnd.x][ptEnd.y];
  429.         while(lowvalue>0)
  430.         {
  431.             found=false;
  432.             do
  433.             {
  434.                 do
  435.                 {
  436.                     //pick a random neighbor
  437.                     nx=rand()%3-1;
  438.                     ny=rand()%3-1;
  439.                 }while((nx==0 && ny==0) || (ptPath.x+nx)<0 || (ptPath.x+nx)>=MAPWIDTH || (ptPath.y+ny)<0 || (ptPath.y+ny)>=MAPHEIGHT);
  440.                 //check to see if the value is lower
  441.                 if(MapPath[ptPath.x+nx][ptPath.y+ny]<lowvalue)
  442.                 {
  443.                     //found!
  444.                     found=true;
  445.                     //set tile to path tile
  446.                     Map[ptPath.x][ptPath.y]=TILEPATH;
  447.                     //move the path
  448.                     ptPath.x+=nx;
  449.                     ptPath.y+=ny;
  450.                     lowvalue=MapPath[ptPath.x][ptPath.y];
  451.                 }
  452.             }
  453.             while(!found);
  454.         }
  455.         //replace the end tile
  456.         Map[ptEnd.x][ptEnd.y]=TILEEND;
  457.     }
  458. }
  459.  
  460. void PutTile(int x,int y,int tilenum)//put a tile
  461. {
  462.     //mask first
  463.     BitBlt(gdicMap,x*TILEWIDTH,y*TILEHEIGHT,TILEWIDTH,TILEHEIGHT,gdicAI,tilenum*16,16,SRCAND);
  464.     //then image
  465.     BitBlt(gdicMap,x*TILEWIDTH,y*TILEHEIGHT,TILEWIDTH,TILEHEIGHT,gdicAI,tilenum*16,0,SRCPAINT);
  466. }
  467.  
  468. void DrawMap()//draw the map
  469. {
  470.     //loop through the positions
  471.     for(int x=0;x<MAPWIDTH;x++)
  472.     {
  473.         for(int y=0;y<MAPHEIGHT;y++)
  474.         {
  475.             //place the base tile first
  476.             if(Map[x][y]!=TILEEMPTY && Map[x][y]!=TILESELECT)
  477.             {
  478.                 PutTile(x,y,TILEEMPTY);
  479.             }
  480.             //place the tile
  481.             PutTile(x,y,Map[x][y]);
  482.         }
  483.     }
  484.     //clear out the bottom row
  485.     RECT rcTemp;
  486.     SetRect(&rcTemp,0,TILEHEIGHT*MAPHEIGHT,TILEWIDTH*MAPWIDTH,TILEHEIGHT+TILEHEIGHT*MAPHEIGHT);
  487.     FillRect(gdicMap,&rcTemp,(HBRUSH)GetStockObject(BLACK_BRUSH));
  488.     //place the toolbar
  489.     for(int count=0;count<4;count++)
  490.     {
  491.         //put the tile
  492.         PutTile(count,MAPHEIGHT,count);        
  493.     }
  494.     //put the seleciton
  495.     PutTile(TileSelected,MAPHEIGHT,TILESELECT);
  496. }
  497.  
  498. void PlaceTile(int x,int y, int tilenum)//place a tile on the map
  499. {
  500.     int tx;
  501.     int ty;
  502.     bool hasstart=(tilenum==TILESTART);
  503.     bool hasend=(tilenum==TILEEND);
  504.     //clear some tiles
  505.     for(tx=0;tx<MAPWIDTH;tx++)
  506.     {
  507.         for(ty=0;ty<MAPHEIGHT;ty++)
  508.         {
  509.             //remove all path tiles
  510.             if(Map[tx][ty]==TILEPATH) Map[tx][ty]=TILEEMPTY;
  511.             //if we are placing the start, remove all start tiles
  512.             if(Map[tx][ty]==TILESTART && tilenum==TILESTART) Map[tx][ty]=TILEEMPTY;
  513.             //if we are placing the end, remove all end tiles
  514.             if(Map[tx][ty]==TILEEND && tilenum==TILEEND) Map[tx][ty]=TILEEMPTY;
  515.         }
  516.     }
  517.     //place the tile
  518.     Map[x][y]=tilenum;
  519.     //check for starting and ending point
  520.     for(tx=0;tx<MAPWIDTH;tx++)
  521.     {
  522.         for(ty=0;ty<MAPHEIGHT;ty++)
  523.         {
  524.             //check for a start tile
  525.             if(Map[tx][ty]==TILESTART) hasstart=true;
  526.             //check for an end tile
  527.             if(Map[tx][ty]==TILEEND) hasend=true;
  528.         }
  529.     }
  530.     //find the path
  531.     if(hasstart && hasend) FindPath();
  532.     //draw the map
  533.     DrawMap();
  534.     //invalidate the window rect
  535.     InvalidateRect(hWndMain,NULL,FALSE);
  536. }
  537.  
  538.